package com.hanserwei.han_picture.service.seviceImpl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hanserwei.han_picture.domain.entity.po.Picture;
import com.hanserwei.han_picture.domain.entity.po.Space;
import com.hanserwei.han_picture.domain.entity.po.User;
import com.hanserwei.han_picture.domain.entity.vo.*;
import com.hanserwei.han_picture.domain.exception.ApiException;
import com.hanserwei.han_picture.domain.request.space.*;
import com.hanserwei.han_picture.enums.ResponseCodeEnum;
import com.hanserwei.han_picture.mapper.SpaceMapper;
import com.hanserwei.han_picture.service.PictureService;
import com.hanserwei.han_picture.service.SpaceAnalyzeService;
import com.hanserwei.han_picture.service.SpaceService;
import com.hanserwei.han_picture.service.UserService;
import com.hanserwei.han_picture.utils.ThrowUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceAnalyzeService {


    private final UserService userService;
    private final SpaceService spaceService;
    private final PictureService pictureService;

    /**
     * 根据查询条件不同进行封装
     *
     * @param request 空间分析请求参数
     * @param wrapper 查询条件
     */
    private void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest request, QueryWrapper<Picture> wrapper) {
        if (request.isQueryAll()) {
            // 分析全部空间, 无查询条件
            return;
        }
        if (request.isQueryPublic()) {
            // 查询公共图库
            wrapper.isNull("space_id");
            return;
        }
        if (request.getSpaceId() != null) {
            // 查询私人图库
            wrapper.eq("space_id", request.getSpaceId());
            return;
        }
        throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "查询条件错误,未指定查询条件！");
    }

    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest request, User loginUser) {
        // 1.参数校验
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "用户未登录！");
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        boolean queryPublic = request.isQueryPublic();
        boolean queryAll = request.isQueryAll();
        if (queryAll || queryPublic) {
            // 全空间或者公共图库分析
            this.checkSpaceAuth(request, loginUser);
            QueryWrapper<Picture> wrapper = new QueryWrapper<>();
            wrapper.select("pic_size");
            this.fillAnalyzeQueryWrapper(request, wrapper);
            // 查询
            List<Object> picSize = pictureService.getBaseMapper().selectObjs(wrapper);
            // 数据处理
            // 同居已使用的大小
            long usedSize = picSize.stream().mapToLong(i -> (Long) i).sum();
            // 统计已使用数目
            long usedCount = picSize.size();
            // 封装返回结果
            SpaceUsageAnalyzeResponse response = new SpaceUsageAnalyzeResponse();
            response.setUsedSize(usedSize);
            response.setUsedCount(usedCount);
            // 全空间 或 公共图库 容量无上限
            response.setMaxSize(null);
            response.setMaxCount(null);
            response.setSizeUsageRatio(null);
            response.setCountUsageRatio(null);
            return response;
        } else {
            // 私人图库分析
            Long spaceId = request.getSpaceId();
            ThrowUtils.throwIf(spaceId == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误,空间id为空！");
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ResponseCodeEnum.INVALID_PARAMETER, "空间不存在！");
            // 权限校验
            this.checkSpaceAuth(request, loginUser);
            // 封转返回结果
            SpaceUsageAnalyzeResponse response = new SpaceUsageAnalyzeResponse();
            response.setUsedSize(space.getTotalSize());
            response.setMaxSize(space.getMaxSize());
            response.setUsedCount(space.getTotalCount());
            response.setMaxCount(space.getMaxCount());
            double sizeRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            double countRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            response.setSizeUsageRatio(sizeRatio);
            response.setCountUsageRatio(countRatio);
            return response;
        }
    }

    /**
     * 空间分析权限校验
     *
     * @param request   空间分析请求参数
     * @param loginUser 登录用户
     */
    private void checkSpaceAuth(SpaceAnalyzeRequest request, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "请先登录");
        Long spaceId = request.getSpaceId();
        boolean queryPublic = request.isQueryPublic();
        boolean queryAll = request.isQueryAll();
        if (queryAll || queryPublic) {
            // 需要管理员权限
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ResponseCodeEnum.UNAUTHORIZED, "无权限！！");
        } else {
            if (spaceId != null) {
                // 仅空间创建人或管理员可访问
                Space space = spaceService.getById(spaceId);
                ThrowUtils.throwIf(space == null, ResponseCodeEnum.INVALID_PARAMETER, "空间不存在");
                ThrowUtils.throwIf(!loginUser.getId().equals(space.getUserId()) && !userService.isAdmin(loginUser),
                        ResponseCodeEnum.UNAUTHORIZED, "无权限操作该空间");
            }
        }
    }

    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest request, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "请先登录");
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        // 权限校验
        this.checkSpaceAuth(request, loginUser);
        // 查询
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        this.fillAnalyzeQueryWrapper(request, wrapper);
        wrapper.select("category", "count(*) as count", "sum(pic_size) as totalSize").groupBy("category");
        return pictureService.getBaseMapper().selectMaps(wrapper)
                .stream()
                .map(result -> {
                    String category = result.get("category") != null ? result.get("category").toString() : "未分类";
                    long count = Long.parseLong(result.get("count").toString());
                    long totalSize = Long.parseLong(result.get("totalSize").toString());
                    return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
                }).collect(Collectors.toList());
    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest request, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "请先登录");
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        this.checkSpaceAuth(request, loginUser);
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        this.fillAnalyzeQueryWrapper(request, wrapper);
        wrapper.select("tags");
        // 查询所有符合条件的标签
        List<String> tagsList = pictureService.getBaseMapper().selectObjs(wrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .toList();
        // 2. 合并所有标签并统计使用次数(k, v : 标签名, 使用次数)
        // 扁平化: ["java", "python"], ["java", "php"] ===> ["java", "python", "php"]
        Map<String, Long> tagsMap = tagsList.stream()
                .flatMap(tag -> JSONUtil.toList(tag, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        // 3. 转换为响应对象, 按使用次数降序排序
        return tagsMap.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest request, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "请先登录");
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        this.checkSpaceAuth(request, loginUser);
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        wrapper.select("pic_size");
        this.fillAnalyzeQueryWrapper(request, wrapper);
        List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(wrapper)
                .stream()
                .map(obj -> ((Number) obj).longValue())
                .toList();
        // 定义有序的图片范围
        Map<String, Long> sizeRange = picSizeList.stream()
                .collect(Collectors.groupingBy(
                        size -> {
                            if (size < 100 * 1024) {
                                return "<100KB";
                            } else if (size < 500 * 1024) {
                                return "100KB - 500KB";
                            } else if (size < 1024 * 1024) {
                                return "500KB - 1MB";
                            } else {
                                return ">1MB";
                            }
                        },
                        Collectors.counting()
                ));
        return sizeRange.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest request, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "请先登录");
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        this.checkSpaceAuth(request, loginUser);
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        Long userId = request.getUserId();
        wrapper.eq(ObjUtil.isNotEmpty(userId), "user_id", userId);
        this.fillAnalyzeQueryWrapper(request, wrapper);
        String dimension = request.getTimeDimension();
        switch (dimension) {
            case "day":
                wrapper.select("DATE_FORMAT(create_time, '%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                wrapper.select("YEARWEEK(create_time) as period", "count(*) as count");
                break;
            case "month":
                wrapper.select("DATE_FORMAT(create_time, '%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "时间维度错误");
        }
        // 分组并排序
        wrapper.groupBy("period").orderByDesc("period");
        // 查询结果并转换
        return pictureService.getBaseMapper().selectMaps(wrapper)
                .stream()
                .map(result -> {
                    String period = result.get("period").toString();
                    long count = ((Number) result.get("count")).longValue();
                    return new SpaceUserAnalyzeResponse(period, count);
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest request, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ResponseCodeEnum.UNAUTHORIZED, "请先登录");
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误");
        // 仅管理员可用
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ResponseCodeEnum.UNAUTHORIZED, "无权限");
        // 构造查询条件
        QueryWrapper<Space> wrapper = new QueryWrapper<>();
        wrapper.select("id", "space_name", "total_size","total_count", "user_id")
                .orderByDesc("total_size")
                // 获取前 N 个
                .last("limit " + request.getTopN());
        // 查询结果
        return spaceService.list(wrapper);
    }
}
